using System;
using System.Diagnostics.Contracts;

namespace Beaker
{
	/// <summary>
	/// 
	/// </summary>
	[ContractClass(typeof(MaybeContract))]
	public interface IMaybe
	{
		/// <summary>
		/// Gets if the maybe has a value.
		/// </summary>
		bool HasValue { get; }

		/// <summary>
		/// Get the value of the maybe.
		/// </summary>
		/// <exception cref="InvalidOperationException">Thrown when the Maybe has no value.</exception>
		object Value { get; }

		/// <summary>
		/// Get the underlying type of the maybe.
		/// </summary>
		/// <returns>The type of the maybe.</returns>
		Type GetUnderlyingType();
	}
	
	/// <summary>
	/// Code Contracts for the <see cref="IMaybe"/> interface.
	/// </summary>
	[ContractClassFor(typeof(IMaybe))]
	abstract class MaybeContract
		: IMaybe
	{
		public bool HasValue
		{
			get { throw new NotImplementedException(); }
		}

		public object Value
		{
			get
			{
				Contract.Requires<InvalidOperationException>(HasValue == true, "Cannot get the value of a maybe that has no value.");
				throw new NotImplementedException();
			}
		}

		public Type GetUnderlyingType()
		{
			Contract.Ensures(Contract.Result<Type>() != null);
			throw new NotImplementedException();
		}
	}

}